#!/usr/bin/ruby -w
# Optiminimal ruby command line twitter
require 'yaml'
require 'pathname'
require 'rubygems'
require 'json'

#require 'rdoc/usage'
#require 'date'

class MessageItem
	
	def initialize( item, index )
		@index = index
		@user = item['user']['name']
		@id = item['id']
		@text = item['text']
	end
	
	def index
		@index
	end
	
	def user
		@user
	end
	
	def text
		@text
	end
	
	def id
		@id
	end
	
	def to_a
		[ index, user, text ]
	end
end

class App
	
	APP_NAME = "Imaichi Twitter Command Line Client [Ruby]"
	VER  = "0.3"
	
	URL_UPDATE  = "http://twitter.com/statuses/update.xml"
	URL_USER_TIMELINE = "http://twitter.com/statuses/user_timeline.json"
	URL_FRIENDS_TIMELINE = "http://twitter.com/statuses/friends_timeline.json"
	URL_SHORTEN_API = "http://bit.ly/api?url="
	
	def initialize( arguments, stdin )
		@args = arguments
		@stdin = stdin
		@config_file = ".twitterrb.yml"
		@cache_file = ".twitter.cache"
		@pn = Pathname.new __FILE__
	end

	def run
		if !config = check_config_file( @config_file )
			create_config_file( @config_file )
		end


		if !config[ "user" ] && !config[ "pass" ]
			exit
		end
	
		case @args[0]
			when /^\/clear_config$/
				create_config_file( @config_file )
		
			when /^\/env(|ironment)$/
				ENV.to_hash.each do |key, value|
					puts("#{key}\t#{value}")
				end

			when /^\/who(|ami)$/
				puts "Username: " + config[ "user" ]
				puts "Password: " + config[ "pass" ]
	
			when /^\/h(|elp)$/
				output_help

			when /^\/v(|ersion)$/
				puts "Current Version of #{APP_NAME} [Ruby] is #{VER}"
	
			when /^\/m(|e)$/ 
				result = %x[curl -s -S -u #{config[ 'user' ]}:#{config[ 'pass' ]} #{URL_USER_TIMELINE}]
				puts "Failure" if result == nil

				cache_write( result )
				json = JSON.parse(result)
		
				count = 0
				
				message_items = Array.new
				message_items << ['index', 'user', 'tweet']
				
				json.each do |item|
	
					message_item = MessageItem.new( item, count )
					message_items << message_item.to_a
					count += 1
					#item.each do |key,id|
					#	 puts "#{key} => #{id}"
					#end
		
				end
				
				puts table_to_pipes( message_items )

			when /^\/del(|ete)$/
				index = @args[1]
				id = get_id_by_index( index )
				result = %x[curl -s -S -u #{config[ 'user' ]}:#{config[ 'pass' ]}  --http-request DELETE http://twitter.com/statuses/destroy/#{id}.json]
				json = JSON.parse(result)
				if json["error"]
					puts json["error"] 
					puts json["request"] 
				else
					cache_remove_by_index( index )
					puts "#{id} deleted"
				end
		
			when /^\/a(|dd)$/
			
				args = @args.clone
				args.delete_at( 0 )
				text = args.join(' ')

				if text.length >= 144
			  	puts "Limit post to 144 chars."
				else
					text = shorten_urls( text )

					#puts "curl -s -S -u #{config[ 'user' ]}:#{config[ 'pass' ]} -d status=\"#{text}\" #{URL_UPDATE}"
					result = %x[curl -s -S -u #{config[ "user" ]}:#{config[ "pass" ]} -d status="#{text}" #{URL_UPDATE}]
					puts "Update Failure" if result.grep(/text/) == nil
				end
			when /^\/cached$/
				
				json = JSON.parse(cache_read())
		
				count = 0
				
				message_items = Array.new
				message_items << ['index', 'user', 'tweet']
				
				json.each do |item|
					message_item = MessageItem.new( item, count )
					message_items << message_item.to_a
					count += 1
				end

				
				puts table_to_pipes( message_items )	
			else
				
				result = %x[curl -s -S -u #{config[ 'user' ]}:#{config[ 'pass' ]} #{URL_FRIENDS_TIMELINE}]
				puts "Failure" if result == nil
				json = JSON.parse(result)
		
				count = 0
				
				message_items = Array.new
				message_items << ['user', 'tweet']
				
				json.each do |item|
	
					message_item = MessageItem.new( item, count )
					message_items << [message_item.user, message_item.text ] 
					count += 1
					#item.each do |key,id|
				 	#	 puts "#{key} => #{id}"
					#end
				end
				puts table_to_pipes( message_items )
				
		end
	end
	
	private
	def create_config_file( filename )
		print "\e[2J\e[f" 
		puts "Setup #{APP_NAME}"
		puts "Creating config file at #{ENV['HOME']}/#{filename}"
		puts "* * * * * * * * * * * * * * * * * * * * * * * * * "
		puts "Twitter username:"
		$stdout.flush
		user = @stdin.gets.chomp
	
		puts "Twitter password:"
		$stdout.flush
		pass = @stdin.gets.chomp
	
		config = {"user" => user, "pass"=>pass}
		p config.to_yaml
		open("#{ENV['HOME']}/#{filename}", 'w+') {|f| YAML.dump(config, f)}
	end

	def check_config_file( filename )
		begin
			conf = open("#{ENV['HOME']}/#{filename}") {|f| YAML.load(f) }
			#conf.each{ |k, v| puts "#{k} => #{v}" }
			return conf
		rescue => err
			#puts "Exception: #{err}"
			return false
		end
	end

	def cache_write( result )
		File.open("#{ENV['HOME']}/#{@cache_file}", 'w+') {|f| f.write(result) }
	end

	def cache_read
		f = File.open("#{ENV['HOME']}/#{@cache_file}")
		return f.gets
	end

	def cache_remove_by_index( index )
		json = JSON.parse( cache_read )
		json.delete_at( index.to_i )
		cache_write( JSON.generate( json ) )
	end

	def get_id_by_index( index )
		json = JSON.parse( cache_read )
		return json[ index.to_i ][ "id" ]
	end
	
	def terminal_size
		%x{stty size}.split.collect { |x| x.to_i }
	end
		
	def output_help
		width = terminal_size[1]
		puts "Options:\n"[0..width].center(width)
		puts "#{APP_NAME} Help: \n"[0..width].center(width)
		puts 
		puts '[ make a tweet /a or /add ]'[0..width].center(width)
		puts "#{@pn.basename} /add This is my message."[0..width].center(width)
		puts 
		puts '[ view friends timeline ]'[0..width].center(width)
		puts "#{@pn.basename}"[0..width].center(width)
		puts 
		puts '[ view personal timeline /m or /me ]'[0..width].center(width)
		puts "#{@pn.basename} /me"[0..width].center(width)
		puts
		puts "[ delete a tweet /del or /delete ]"[0..width].center(width)
		puts "#{@pn.basename} /delete [index]"[0..width].center(width)
		puts "params [index] of the tweet ( as fetched by #{@pn.basename} /me )"[0..width].center(width)
		puts "if no [index] is passed, last tweet will be deleted"[0..width].center(width)
		puts 
		puts "[ show version /v or /version ]"[0..width].center(width)
		puts "#{@pn.basename} /version"[0..width].center(width)
		puts 
		puts "[ reset configuration ]"[0..width].center(width)
		puts "#{@pn.basename} /clear_config"[0..width].center(width)
	end

	def shorten_urls( text )
		#url_pattern = /(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?/ix
		url_pattern = /((https?:\/\/|www\.)([-\w\.]+)+(:\d+)?(\/([\w\/_\.]*(\?\S+)?)?)?)/ix
		matches = Array.new
		matches = text.split.grep(url_pattern)
		matches.each do |match|
			#puts ">> #{match}"
			result = %x[curl -s -S "#{URL_SHORTEN_API}#{match}"]
			if result == nil
				puts "URL_SHORTEN_API Failure"
				break
			end
			text = text.gsub(match, result.to_s )
		end
		
		return text
	end
	
	def row_to_pipes(row, widths)
		widths = widths.dup

		return ' ' + row.map{|c|
			w = widths.shift 
			justify( c, w )
			
			}.join(' | ') + ' '

	end

	def table_to_pipes(table)
		
		widths = (0 ... table.first.length).map do |x|
			table.sort_by{|q| q[x].to_s.length }.last[x].to_s.length
		end
		
		count = 0
		out = ""
		table.map{|r| 
			
			out += row_to_pipes( r, widths )+ "\n"
			if count == 0
				
				total_width = 0
				widths.size.times do |i|
					total_width += widths[ i ]
				end
				
				#puts "#{total_width} > #{terminal_size[1]}"
				
				terminal_size[1].times do |i|
					out +="-"
				end
				
				out += "\n"
			end
			
			count += 1
		}.join("\n")
		
		return out
	end
	
	def justify(obj,w)
		case obj
			when Fixnum
				obj.to_s.rjust(w) #"#{obj} - #{w}"
			else
				obj.to_s.ljust(w)
			end
	end
	
end

app = App.new( ARGV, STDIN )
app.run

